﻿using RProxy.Proxy.PortMap;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Net;
using System.Threading;

namespace DSVISUAL.LocalDNS.Services
{
    public class PortMapService
    {
        static string f = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "port_map_service.autostart");
        public static void SaveDataSource(DataTable dt)
        {
            dt.WriteXml("portmap.xml");
        }
        public static void SetIsAutoStart(bool autoStart)
        {
            if (autoStart)
            {
                if (File.Exists(f))
                {
                    File.Delete(f);
                }
            }
            else
            {
                if (!File.Exists(f))
                    File.Create(f).Dispose();
            }
        }
        public static bool GetIsAutoStart()
        {
            return File.Exists(f);
        }

        public static DataTable LoadDataSource()
        {
            DataTable dt = null;
            if (File.Exists("portmap.xml"))
            {
                dt = new DataTable("PORTMAP");
                dt.Columns.Add("ID");
                dt.Columns.Add("LISTEN_ADDR");
                dt.Columns.Add("LISTEN_PORT");
                dt.Columns.Add("TARGET_ADDR");
                dt.Columns.Add("TARGET_PORT");
                dt.Columns.Add("ENABLED");
                dt.Columns.Add("STATUS");
                dt.ReadXml("portmap.xml");
                foreach (DataRow item in dt.Rows)
                {
                    item["STATUS"] = "STOPPED";
                }
            }
            else
            {
                dt = new DataTable("PORTMAP");
                dt.Columns.Add("ID");
                dt.Columns.Add("LISTEN_ADDR");
                dt.Columns.Add("LISTEN_PORT");
                dt.Columns.Add("TARGET_ADDR");
                dt.Columns.Add("TARGET_PORT");
                dt.Columns.Add("ENABLED");
                dt.Columns.Add("STATUS");
            }
            if (dt.Rows.Count == 0)
            {
                var row = dt.NewRow();
                row["ID"] = 1;
                row["LISTEN_ADDR"] = "127.0.0.1";
                row["LISTEN_PORT"] = "6379";
                row["TARGET_ADDR"] = "10.0.0.9";
                row["TARGET_PORT"] = "6379";
                row["ENABLED"] = true;
                row["STATUS"] = "STOPPED";
                dt.Rows.Add(row);
                dt.WriteXml("portmap.xml");
            }
            return dt;
        }
        public static Dictionary<int, PortMapListener> Listeners = new Dictionary<int, PortMapListener>();
        public static int Start(DataTable dt)
        {
            int threadNum = 0;
            lock (Listeners)
            {
                foreach (DataRow item in dt.Rows)
                {
                    var id = int.Parse(item["ID"].ToString());
                    var addr = item["LISTEN_ADDR"].ToString();
                    var port = int.Parse(item["LISTEN_PORT"].ToString());

                    var targetaddr = item["TARGET_ADDR"].ToString();
                    var targetPort = int.Parse(item["TARGET_PORT"].ToString());

                    var enabled = bool.Parse(item["ENABLED"].ToString());
                    if (enabled)
                    {
                        if (!Listeners.ContainsKey(id))
                        {
                            var target = new IPEndPoint(IPAddress.Parse(targetaddr), targetPort);
                            var listener = new PortMapListener(IPAddress.Parse(addr), port, target);
                            listener.Id = id;
                            var thread = new Thread(ThreadMain);
                            Listeners.Add(id, listener);
                            thread.Start(listener);
                            threadNum++;
                        }
                        item["STATUS"] = "RUNNING";
                    }
                    else
                    {
                        item["STATUS"] = "STOPPED";
                    }
                }
            }
            return threadNum;
        }

        public static void Start(DataRow item)
        {
            lock (Listeners)
            {
                var id = int.Parse(item["ID"].ToString());
                var addr = item["LISTEN_ADDR"].ToString();
                var port = int.Parse(item["LISTEN_PORT"].ToString());

                var targetaddr = item["TARGET_ADDR"].ToString();
                var targetPort = int.Parse(item["TARGET_PORT"].ToString());

                var enabled = bool.Parse(item["ENABLED"].ToString());
                if (enabled)
                {
                    var target = new IPEndPoint(IPAddress.Parse(targetaddr), targetPort);
                    var listener = new PortMapListener(IPAddress.Parse(addr), port, target);
                    var thread = new Thread(ThreadMain);
                    Listeners.Add(id, listener);
                    thread.Start(listener);
                    item["STATUS"] = "RUNNING";
                }
                else
                {
                    item["STATUS"] = "STOPPED";
                }
            }
        }

        private static void ThreadMain(object state)
        {
            var listener = state as PortMapListener;
            listener.Start();
        }

        public static void Stop(int id, DataTable dt = null)
        {
            lock (Listeners)
            {
                if (Listeners.ContainsKey(id))
                {
                    try
                    {
                        Listeners[id].Dispose();
                        Listeners.Remove(id);
                    }
                    catch { }
                    if (dt != null)
                    {
                        foreach (DataRow item in dt.Rows)
                        {
                            if (item["ID"].ToString() == id.ToString())
                            {
                                item["STATUS"] = "STOPPED";
                            }
                        }
                    }
                }
            }
        }

        public static void StopAll(DataTable dt = null)
        {
            lock (Listeners)
            {
                foreach (var item in Listeners.Values)
                {
                    try
                    {
                        item.Dispose();
                    }
                    catch { }
                }
                Listeners.Clear();
                if (dt != null)
                {
                    foreach (DataRow item in dt.Rows)
                    {
                        item["STATUS"] = "STOPPED";
                    }
                }
            }
        }
    }
}
